package avicit.bdp.dgs.qa.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.dto.request.dds.ProcessSchedulerDto;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.dds.api.ProcessDefinitionApi;
import avicit.bdp.dds.api.SchedulerApi;
import avicit.bdp.dds.dispatch.enums.ReleaseState;
import avicit.bdp.dgs.qa.dao.JobDAO;
import avicit.bdp.dgs.qa.dao.SchedulerDAO;
import avicit.bdp.dgs.qa.dto.JobDTO;
import avicit.bdp.dgs.qa.dto.SchedulerDTO;
import avicit.bdp.dgs.qa.utils.constant.QaConstant;
import avicit.bdp.dgs.qa.utils.enums.SchedulerType;
import avicit.bdp.dgs.qa.utils.enums.SubscribeType;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.api.system.impl.SystemConstant;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.PojoUtil;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2023-03-30
 * @类说明：SchedulerService
 * @修改记录：
 * @注意事项：质量作业JobId == 调度配置表（id， jobId） == DDS中调度配置表（id，processDefinitonId）
 * @主要功能：质量作业调度Service
 */
@Service
public class SchedulerService extends BaseService<SchedulerDAO, SchedulerDTO> {
    private static final Logger logger = LoggerFactory.getLogger(SchedulerService.class);

    @Autowired
    private ConvertColumnClient convertColumnClient;

    /**
     * dds中调度配置API接口
     */
    @Autowired
    private SchedulerApi schedulerApi;
    @Autowired
    private ProcessDefinitionApi processDefinitionApi;

    @Autowired
    private JobDAO jobDAO;

    /**
     * 新增/修改调度配置
     * 注意：根据jobId确定是新增还是修改
     * @param schedulerDTO
     * @return
     */
    @Transactional
    public boolean saveScheduler(SchedulerDTO schedulerDTO) {
        checkAddScheduler(schedulerDTO);

        persist2Db(schedulerDTO);


        updatJobAttribute(schedulerDTO);

        return true;
    }

    /**
     * 查看调度配置详情
     * @param jobId
     * @return
     */
    @Transactional
    public Map getScheduleDetail(String jobId) {
        if (StringUtils.isBlank(jobId)) {
            return new HashMap();
        }

        // 查询dgs中调度调度配置
        Map<String, Object> retMap = new HashMap<>();
        SchedulerDTO schedulerDTO = this.selectByPrimaryKey(jobId);
        if (schedulerDTO == null) {
            return retMap;
        }
        valueConvert(Arrays.asList(schedulerDTO));
        retMap.put("id", schedulerDTO.getId());
        retMap.put("jobId", schedulerDTO.getJobId());
        retMap.put("type", schedulerDTO.getType());
        retMap.put("typeName", SchedulerType.getDescByCode(schedulerDTO.getType()));

        // 自动执行，特殊处理，不需要获取DDS调度配置
        if (SchedulerType.AUTO.getCode() == schedulerDTO.getType()) {
            return retMap;
        }

        // 查询dds中调度调度配置
        List<Map<String, Object>> list = this.getScheduleListByJobId(jobId);
        if (CollectionUtils.isEmpty(list)) {
            return retMap;
        }
        Map map = list.get(0);
        retMap.putAll(map);
        retMap.put("failureStrategy", map.get("failureStrategy"));
        retMap.put("warningType", map.get("warningType"));
        retMap.put("processInstancePriority", map.get("processInstancePriority"));
        logger.debug("查询DDS中调度配置成功,jobId=" + jobId);

        return retMap;
    }

    /**
     * 删除调度配置信息
     * 注意：
     *  1、作业下线offline
     *  2、删除定时配置
     * @param jobId
     */
    @Transactional
    public void deleteSchedulerByJobId(String jobId) {
        if (StringUtils.isBlank(jobId)) {
            return;
        }

        SchedulerDTO schedulerDTO = this.selectByPrimaryKey(jobId);
        if (schedulerDTO != null) {
            this.mapper.deleteSchedulerByCond(jobId);

            // 删除定时调度信息
            if (SchedulerType.PERIOD.getCode() == schedulerDTO.getType()) {
                List<Map<String, Object>> list = this.getScheduleListByJobId(jobId);
                if (CollectionUtils.isNotEmpty(list)) {
                    releaseDdsTaskInner(jobId, 0);// 任务下线
                    this.schedulerApi.deleteScheduleById(jobId); // 删除定时配置
                }
            }
        }
    }

    @Transactional
    public Map<String, Object> setScheduleState(String projectId, String schedulerId, ReleaseState state) {
        if (StringUtils.isEmpty(projectId)) {
            projectId = QaConstant.DEFAULT_PROJECT_ID;
        }
        if (StringUtils.isEmpty(schedulerId)) {
            throw new BusinessException("定时配置ID为空");
        }

        if (state == ReleaseState.OFFLINE) {
            logger.warn("停用定时任务,projectId={},schedulerId:{}", projectId, schedulerId);
            return this.schedulerApi.offline(projectId, schedulerId);
        }
        if (state == ReleaseState.ONLINE) {
            logger.warn("启用定时任务,projectId={},schedulerId:{}", projectId, schedulerId);
            return this.schedulerApi.online(projectId, schedulerId);
        }

        return null;
    }

    /**
     * 根据流程id获取定时任务列表
     * @param jobId 流程id
     * @return 定时任务列表
     */
    private List<Map<String, Object>> getScheduleListByJobId(String jobId) {
        QueryRespBean<Map<String, Object>> mapQueryRespBean = schedulerApi.queryScheduleListPaging(jobId, null, 1, 10);
        return mapQueryRespBean.getResult().getResult();
    }

    /**
     * 新增/修改时合法性检查
     * @param schedulerDTO
     */
    private void checkAddScheduler(SchedulerDTO schedulerDTO) {
        if (schedulerDTO == null) {
            throw new BusinessException("入参为空.");
        }
        if (StringUtils.isBlank(schedulerDTO.getJobId())) {
            throw new BusinessException("质量作业ID为空.");
        }
        if (schedulerDTO.getType() == null) {
            throw new BusinessException("调度类型为空.");
        }
    }

    /**
     * 持久化到DB
     * @param schedulerDTO
     */
    private void persist2Db(SchedulerDTO schedulerDTO) {
        if (schedulerDTO == null) {
            return;
        }

        SchedulerDTO queryRet = this.selectByPrimaryKey(schedulerDTO.getJobId());
        if (queryRet == null) {
            // 创建
            save2Db(schedulerDTO);
        } else {
            // 更新
            update2Db(schedulerDTO);
        }
    }

    /**
     * 持久化DB
     * @param schedulerDTO
     */
    private void save2Db(SchedulerDTO schedulerDTO) {
        if (schedulerDTO == null) {
            return;
        }

        // 持久化质量作业调度配置
        schedulerDTO.setId(schedulerDTO.getJobId());
        this.insert(schedulerDTO);

        // 创建dds中定时调度
        if (schedulerDTO.getType() == SchedulerType.PERIOD.getCode()) {
            ProcessSchedulerDto processSchedulerDto = schedulerDTO.getProcessSchedulerDto();
            processSchedulerDto.setId(schedulerDTO.getJobId());
            processSchedulerDto.setProcessDefinitionId(schedulerDTO.getJobId());

            this.schedulerApi.createSchedule(processSchedulerDto);
        }

        // 审计日志
        BdpLogUtil.log4Insert(schedulerDTO);
    }

    /**
     * 持久化DB
     * @param schedulerDTO
     */
    private void update2Db(SchedulerDTO schedulerDTO) {
        if (schedulerDTO == null) {
            return;
        }

        schedulerDTO.setId(schedulerDTO.getJobId());
        SchedulerDTO oldDto = this.selectByPrimaryKey(schedulerDTO.getJobId());
        if (oldDto == null) {
            throw new BusinessException("根据ID未找到调度信息，id=" + schedulerDTO.getId() + "，更新失败");
        }

        // 查询dds中调度调度配置
        ProcessSchedulerDto processSchedulerDto = schedulerDTO.getProcessSchedulerDto();
        if (processSchedulerDto != null) {
            processSchedulerDto.setId(schedulerDTO.getJobId());
            processSchedulerDto.setProcessDefinitionId(schedulerDTO.getJobId());
            List<Map<String, Object>> list = this.getScheduleListByJobId(schedulerDTO.getJobId());
            if (CollectionUtils.isNotEmpty(list)) {
                // 创建dds中调度配置
                this.schedulerApi.updateSchedule(processSchedulerDto);
            } else {
                // 更新dds中调度配置
                this.schedulerApi.createSchedule(processSchedulerDto);
            }
        }

        // 规则持久化
        this.updateByPrimaryKeySelective(schedulerDTO);

        // 审计日志
        BdpLogUtil.log4Update(schedulerDTO, oldDto);
    }

    /**
     * 更新质量作业中调度类型字段
     * @param schedulerDTO
     */
    @SuppressWarnings("不应直接调用JobDAO，而是通过Service调用，后续优化")
    private void updatJobAttribute(SchedulerDTO schedulerDTO) {
        if (schedulerDTO == null) {
            return;
        }

        JobDTO jobDTO = this.jobDAO.selectByPrimaryKey(schedulerDTO.getJobId());
        if (jobDTO != null) {
            jobDTO.setSchedulerType(schedulerDTO.getType());
            PojoUtil.setSysProperties(schedulerDTO, PlatformConstant.OpType.update);
            this.jobDAO.updateByPrimaryKeySelective(jobDTO);
        }
    }

    /**
     * dds任务上线/下线
     * @param processDefinitonId
     * @param releaseState  0：offline；1：online
     * @return
     */
    private String releaseDdsTaskInner(String processDefinitonId, Integer releaseState) {
        // 0：offline；1：online
        boolean result = this.processDefinitionApi.releaseProcessDefinition(processDefinitonId, releaseState);
        if (result) {
            return "上线成功。";
        }

        return "上线失败。";
    }

    /**
     * 通过平台API将字段值转换为名称，包括通用选择组件、通用代码
     * @param dtoList
     */
    private void valueConvert(List<SchedulerDTO> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }

        // 设置创建者名称
        Map<String, Set<String>> convertFormData = new HashMap<>();
        for (SchedulerDTO dto : dtoList) {
            BusinessUtil.createConvertSet(convertFormData, SystemConstant.USER, dto.getCreatedBy());
        }
        if (convertFormData.size() > 0) {
            //获取请求结果
            Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
            //循环设置Alias或Name的值
            for (SchedulerDTO dto : dtoList) {
                dto.setCreatedBy(BusinessUtil.convertFormat(convertResultData, SystemConstant.USER, dto.getCreatedBy()));
            }
        }

        // 设置枚举类型
        for (SchedulerDTO dto : dtoList) {
            dto.setTypeName(SubscribeType.getDescByCode(dto.getType()));
        }
    }
}
